﻿#ifndef __INC_QG_DX9_MTRL_H__
#define __INC_QG_DX9_MTRL_H__

#ifdef _MSC_VER
#pragma once
#endif

#include "qg/qgimage.h"
#include "qg_subtex.h"

//////////////////////////////////////////////////////////////////////////
// 텍스쳐
class DX9Texture : public qgTexture
{
	KCH_SUBCLASS(DX9Texture, qgTexture);
	KCH_FRIEND(DX9Device);

protected:
	kuint				_awidth : 16;
	kuint				_aheight : 16;
	kuint				_adepth : 16;
	kuint				_atmp : 16;

	qgImage*			_img_rsw;
	qgImage*			_img_mip;

	D3DFORMAT			_dx_fmt;
	DWORD				_dx_usage;
	D3DPOOL				_dx_pool;

protected:
	DX9Texture() throw();
	~DX9Texture() throw();

public:
	K_OVR kint KCALL Signal(const char* sig, kpointer arg);

	K_OVR bool EnterMap(qgTextureMap* map, kint flag, kint mips, qgTextureFace face);
	K_OVR bool LeaveMap();

protected:
	bool _InitImage(const char* name, qgImage* img, kint mips, kint flags, DX9Device* dev);
	bool _InitProperty(qgTextureType type, const char* name, kint width, kint height, kint depth, kint mips, kint flags, qgColorFormat fmt, DX9Device* dev);
	bool _CreateInternal(IDirect3DBaseTexture9** ptex, DX9Device* dev);
	bool _CreateTexture(qgImage* img, DX9Device* dev);
	bool _UploadTexture(kint mipno);

	static bool _UploadTexture(IDirect3DBaseTexture9* tex, kint mipno, qgImage* img, bool testautomip, bool isdyn, kint* mips);

public:
	bool _MakeCubeTex(IDirect3DCubeTexture9* tex, DX9Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 모션 텍스쳐, 클래스의 이중 상속...이 있다
class DX9TextureMotion : public DX9Texture, public qgSubTextureMotion
{
	KCH_SUBCLASS(DX9TextureMotion, DX9Texture);
	KCH_FRIEND(DX9Device);

private:
	DX9TextureMotion() throw();
	~DX9TextureMotion() throw();

public:
	K_OVR kint KCALL Signal(const char* sig, kpointer arg);

	K_OVR qgITextureMotion* GetMotion();

	// qgITextureMotion
	K_OVR bool MotionUpdate(float adv);

private:
	bool _CreateMotion(const char* filename, kint flags, DX9Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 뎁스 버퍼
class DX9DepthBuffer : public qgDepthBuffer
{
	KCH_SUBCLASS(DX9DepthBuffer, qgDepthBuffer);
	KCH_FRIEND(DX9Device);
	KCH_FRIEND(DX9TextureOff);

protected:
	DX9DepthBuffer() throw();
	~DX9DepthBuffer() throw();

private:
	K_OVR kint KCALL Signal(const char* sig, kpointer arg);

	bool _Create(kuint width, kuint height, DX9Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 오프 텍스쳐
class DX9TextureOff : public DX9Texture, public qgITextureOff
{
	KCH_SUBCLASS(DX9TextureOff, DX9Texture);
	KCH_FRIEND(DX9Device);
	KCH_FRIEND(DX9Texture);

private:
	IDirect3DSurface9*	_surface;
	DX9DepthBuffer*		_db;

	IDirect3DSurface9*	_lsf;

private:
	DX9TextureOff() throw();
	~DX9TextureOff() throw();

public:
	K_OVR kint KCALL Signal(const char* sig, kpointer arg);

	K_OVR qgITextureOff* GetOff();

	K_OVR bool EnterMap(qgTextureMap* map, kint flag, kint mips, qgTextureFace face);
	K_OVR bool LeaveMap();

	// qgITextureOff
	K_OVR bool EnterOff(kint clearance, const tpl::ColorValue& color);
	K_OVR bool LeaveOff();

private:
	bool _CreateOff(DX9Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 래스터라이저
class DX9Rasz : public qgRasz
{
	KCH_SUBCLASS(DX9Rasz, qgRasz);
	KCH_FRIEND(DX9Device);

private:
	DX9Rasz() throw() {}
	~DX9Rasz() throw() {}
};


//////////////////////////////////////////////////////////////////////////
// 블렌드
class DX9Blnd : public qgBlnd
{
	KCH_SUBCLASS(DX9Blnd, qgBlnd);
	KCH_FRIEND(DX9Device);

private:
	DX9Blnd() throw() {}
	~DX9Blnd() throw() {}
};


//////////////////////////////////////////////////////////////////////////
// 샘플러
class DX9Splr : public qgSplr
{
	KCH_SUBCLASS(DX9Splr, qgSplr);
	KCH_FRIEND(DX9Device);

private:
	DX9Splr() throw() {}
	~DX9Splr() throw() {}
};


//////////////////////////////////////////////////////////////////////////
// 세이더
class DX9Shader : public qgShader
{
	KCH_SUBCLASS(DX9Shader, qgShader);
	KT_DECL_TYPE_INIT(DX9Shader);
	KCH_FRIEND(DX9Device);
	KCH_FRIEND(DX9Layout);
	KCH_INTERN(InclUnit);

public:
	struct MapHandle : public tpl::MemBase
	{
		kint					ref;
		ID3DXConstantTable*		ctbl;
		tpl::Array<qgShaderVar>	vars;	// 고정 길이
	};

private:
	IDirect3DPixelShader9*	_ps;
	IDirect3DVertexShader9*	_vs;

	MapHandle*				_dhp;
	MapHandle*				_dhv;

	bool					_linked;

private:
	DX9Shader() throw();
	~DX9Shader() throw();

public:
	K_OVR bool BindFile(qgShaderType type, const char* filename, kint flags) throw();
	K_OVR bool BindData(qgShaderType type, kconstpointer data, kint size, kint flags) throw();
	K_OVR bool BindShader(qgShaderType type, const char* name) throw();
	K_OVR bool Link();

	K_OVR qgShaderVar* GetVars(kint stage, kint* count);

	void _ProcessMap() throw();

private:
	void _ProcessHandle(MapHandle* h) throw();

	void _PrintError(LPD3DXBUFFER errs, kint errcode, const char* target) throw();
	bool _InternalBindData(qgShaderType type, kconstpointer data, kint size, kint flags) throw();
	bool _CreatePixelShader(kconstpointer data, kint size, CONST D3DXMACRO* mcs, InclUnit& inc, DWORD dw) throw();
	bool _CreateVertexShader(kconstpointer data, kint size, CONST D3DXMACRO* mcs, InclUnit& inc, DWORD dw) throw();
	MapHandle* _AnalyzeData(qgShaderType type, ID3DXConstantTable* ctbl) throw();

	static D3DXMACRO* _MakeDefinition(ConditionArray& conds);
	static DWORD _MakeFlags(kint v);

	static qgShaderData _ShaderTypeToShaderData(const D3DXCONSTANT_DESC& cd);

	static void _RemoveHandle(IUnknown** unk, MapHandle** mh, bool reset);

	static void _InitAutoFunc();
	static kpointer _MatchAutoFunc(qgShaderVar& v);
};

#endif	// __INC_QG_DX9_MTRL_H__
